package com.laicunba.service.jzh.impl;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.laicunba.constant.GloabConstant;
import com.laicunba.pojo.JzhAccountDO;
import com.laicunba.pojo.JzhWithdrawDO;
import com.laicunba.pojo.UserDO;
import com.laicunba.service.UserService;
import com.laicunba.service.impl.BaseServiceImpl;
import com.laicunba.service.jzh.JzhAccountService;
import com.laicunba.service.jzh.JzhBalanceItemService;
import com.laicunba.service.jzh.JzhWithdrawService;
import com.laicunba.service.jzh.SecurityUtils;
import com.laicunba.util.AssertUtil;
import com.laicunba.util.StringUtil;

@Service
public class JzhWithdrawServiceImpl extends BaseServiceImpl implements JzhWithdrawService {
	private static final Logger LOG = Logger.getLogger(JzhWithdrawServiceImpl.class);
	private static final char SPLIT_CHAR = '|';
	@Autowired
	private UserService userService;
	@Autowired
	private JzhAccountService jzhAccountService;

	@Transactional
	@Override
	public ApplyResult createApply(Param param) {
		AssertUtil.assertNotNull(param, "PARAM_NULL");
		AssertUtil.assertNotNull(param.getUid(), "PARAM_UID_NOT_NULL");
		AssertUtil.assertTrue(param.getCentAmt() > 0, "AMT_LESS_ZERO");

		UserDO user = userService.get(UserDO.class, param.getUid());
		AssertUtil.assertNotNull(user, "USER_NOT_EXIST");
		JzhAccountDO jzhAccountDO = jzhAccountService.get(JzhAccountDO.class, user.getId());
		AssertUtil.assertNotNull(jzhAccountDO, "JZH_ACCOUNT_NOT_EXIST");
		AssertUtil.assertTrue(jzhAccountDO.getBalance().multiply(BigDecimal.valueOf(100)).intValue() >= param.getCentAmt(), "NO_MORE_BALANCE");
		String mchntTxnSsn = "O" + Long.toString(System.currentTimeMillis()) + StringUtil.randomNumber(7) + String.format("%05d", param.getSeq());

		StringBuilder signSrc = new StringBuilder();

		signSrc.append(param.getCentAmt()).append(SPLIT_CHAR);
		signSrc.append(param.getBackNotifyUrl()).append(SPLIT_CHAR);
		signSrc.append(user.getMobile()).append(SPLIT_CHAR);
		signSrc.append(GloabConstant.JZH_MCHNT_CD).append(SPLIT_CHAR);
		signSrc.append(mchntTxnSsn).append(SPLIT_CHAR);
		signSrc.append(param.getPageNotifyUrl());

		String signature = SecurityUtils.sign(signSrc.toString());

		JzhWithdrawDO withdrawDO = new JzhWithdrawDO();
		withdrawDO.setCentAmt(param.getCentAmt());
		withdrawDO.setId(mchntTxnSsn);
		withdrawDO.setLoginId(user.getMobile());
		withdrawDO.setUserId(user.getId());
		withdrawDO.setStatus("apply");
		AssertUtil.assertTrue(this.create(withdrawDO), "WITHDRAW_DO_CREATE_FAIL");

		ApplyResult result = new ApplyResult();
		result.setMchntTxnSsn(mchntTxnSsn);
		result.setSignature(signature);
		result.setLoginId(user.getMobile());
		return result;
	}

	@Override
	public boolean verifyFromJzhServer(Result result) {
		AssertUtil.assertTrue(GloabConstant.JZH_MCHNT_CD.equals(result.getMchntCd()), "MCHNT_CD_NOT_MATCH");
		StringBuilder verifySrc = new StringBuilder();
		verifySrc.append(result.getCentAmt()).append(SPLIT_CHAR);
		verifySrc.append(result.getLoginId()).append(SPLIT_CHAR);
		verifySrc.append(result.getMchntCd()).append(SPLIT_CHAR);
		verifySrc.append(result.getMchntTxnSsn()).append(SPLIT_CHAR);
		verifySrc.append(result.getRespCode());
		return SecurityUtils.verifySign(verifySrc.toString(), result.getSignature());
	}

	@Transactional
	@Override
	public boolean onPayoutSuccess(Result result) {
		/**
		 * 这里可能会出现一个很严重的问题，即金账户付出去了，但我们回滚了，请想一个更好的办法
		 */
		AssertUtil.assertNotNull(result, "PARAM_NULL");
		AssertUtil.assertNotEmpty(result.getMchntTxnSsn(), "MCHNT_TXN_SSN_IS_NULL");
		AssertUtil.assertTrue(GloabConstant.JZH_MCHNT_CD.equals(result.getMchntCd()), "MCHNT_CD_NOT_MATCH");
		JzhWithdrawDO withdrawDO = get(JzhWithdrawDO.class, result.getMchntTxnSsn());
		AssertUtil.assertNotNull(withdrawDO, "WITHDRAW_DO_NOT_FOUND");
		AssertUtil.assertTrue(result.getLoginId().equals(withdrawDO.getLoginId()), "LOGIN_ID_NOT_MATCH");
		AssertUtil.assertTrue("apply".equalsIgnoreCase(withdrawDO.getStatus()), "WITHDRAW_STATUS_NOT_APPLY");

		// 立即更新为已提现，在这里不能回滚，以防止出现存管钱被取走，但本地还没取走的情况
		boolean success = onPayoutSuccessAccounting(withdrawDO);
		LOG.info(String.format("withdraw_id:[%s]取现成功本地扣款[%s]", withdrawDO.getId(), success));
		AssertUtil.assertTrue(result.getCentAmt() == withdrawDO.getCentAmt(), "AMT_NOT_MATCH");

		return true;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	@Override
	public boolean onPayoutSuccessAccounting(JzhWithdrawDO withdrawDO) {

		BigDecimal amt = BigDecimal.valueOf(withdrawDO.getCentAmt()).divide(BigDecimal.valueOf(100));
		Map map = new HashMap();
		map.put("id", withdrawDO.getId());
		int effctRows = updateDao.update("JZH_WITHDRAW.update2Transfered", map);
		LOG.info(String.format("[UPDATE_STATUS] id:%s,rows:%s", withdrawDO.getId(), effctRows));
		BigDecimal balanceAmt = jzhAccountService.subtract(withdrawDO.getUserId(), amt, withdrawDO.getId(), "withdraw", "取现");
		return true;
	}

	@Override
	public String makeEchoInfo(BackParam backParam) {
		StringBuffer plain = new StringBuffer();
		plain.append("<plain>");
		plain.append("<resp_code>").append(backParam.getRespCode()).append("</resp_code>");
		plain.append("<mchnt_cd>").append(backParam.getMchntCd()).append("</mchnt_cd>");
		plain.append("<mchnt_txn_ssn>").append(backParam.getMchntTxnSsn()).append("</mchnt_txn_ssn>");
		plain.append("</plain>");
		String signature = SecurityUtils.sign(plain.toString());
		StringBuffer echoStr = new StringBuffer();
		echoStr.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
		echoStr.append("<ap>").append(plain.toString()).append("<signature>").append(signature).append("</signature>").append("</ap>");
		return echoStr.toString();
	}
	
	@Override
	public List<JzhWithdrawDO> findJzhWithdrawList(String userId, int limit, int offset) {
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("userId", userId);
		param.put("limit", limit);
		param.put("offset", offset);
		return queryDao.selectList("JZH_WITHDRAW.findJzhWithdrawList", param);
	}
}
